package ferp.core.ai.strategy;

import ferp.core.ai.strategy.simple.Estimate;
import ferp.core.ai.strategy.simple.SimpleDropping;
import ferp.core.card.Card;
import ferp.core.game.Game;
import ferp.core.player.Hand;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * User: olegs
 * Date: 1/17/13 2:50 PM
 */
public final class Guess
{
  // guess misere declarer hand after drop - the method receives the "full" declarer hand, i.e. with talon
  public static int declarerMisereHand(int hand, int drop)
  {
    int tricks = Estimate.misereHand(hand);

    ArrayList<Card> cards = new ArrayList<Card>(2 * Card.Suit.rising.length);

    // find suits with "holes"
    for (Card.Suit s : Card.Suit.rising)
    {
      int set = Hand.get(hand, s);
      int t = Estimate.misereSuit(set);

      if (t > 0)
      {
        // save 2 highest cards
        Card.Rank highest = Card.Set.highest(set);
        cards.add(Card.card(s, highest));

        Card.Rank lower = Card.Set.lower(set, highest);
        if (lower != null)
          cards.add(Card.card(s, lower));
      }
    }

    // create all card pairs combinations
    HashSet<Integer> pairs = new HashSet<Integer>();
    for (Card c1 : cards)
    {
      Card.Rank highest1 = Card.Set.highest(Hand.get(hand, c1.suit));

      for (Card c2 : cards)
        if (c1 != c2 && (c1.suit == c2.suit || (c1.rank == highest1 && c2.rank == Card.Set.highest(Hand.get(hand, c2.suit)))))
          pairs.add(c1.hash | c2.hash);
    }

    int result = 0;

    if (pairs.size() > 0)
    {
      int delta = 0;

      for (Integer pair : pairs)
      {
        int h = Hand.remove(hand, pair);
        int d = tricks - Estimate.misereHand(h);

        if (result == 0 || d > delta)
        {
          delta = d;
          result = h;
        }
      }
    }
    else
    {
      switch (cards.size())
      {
        case 0:
          // there are no suits with "holes", which means misere can not be caught - we can remove the real drop from the hand
          result = Hand.remove(hand, drop);
          break;

        case 1:
          result = Hand.remove(hand, cards.get(0).hash);

          for (Card.Suit s : Card.Suit.rising)
          {
            int set = Hand.get(hand, s);

            if (set != 0)
            {
              Card.Rank highest = Card.Set.highest(set);
              result = Hand.remove(result, Card.card(s, highest).hash);

              break;
            }
          }
          break;
      }
    }

    return result;
  }

  public static int declarerTrickingHand(int hand, boolean isStarting, int sets)
  {
    dropping.tricks(hand, isStarting, sets, drop);

    return Hand.remove(hand, drop[0] | drop[1]);
  }

  // dropping strategy
  private static final SimpleDropping dropping = new SimpleDropping();
  // guessed drop
  private static final int[] drop = new int[Game.TALON_SIZE];

  public static void main(String[] args)
  {
/*

    for (int i = 255; i >= 0; --i)
    {
      int max = misereTricks[i];

      for (int set = i; set > 0;)
      {
        Card.Rank highest = Card.Set.highest(set);
        int less = Hand.remove(set, highest.hash());

        if (misereTricks[less] > max)
        {
          System.out.println("row #" + i + ", cards: " + Hand.dump(i) + ", tricks: " + max);
          System.out.println("less #" + less + ", cards: " + Hand.dump(less) + ", tricks: " + misereTricks[less]);
          return;
        }

        set = less;
      }
    }
*/
  }
}

